/* This is a very simplified version of the POSIX opendir(),  */
/* readdir(), and closedir() -- for Commodore computers.      */
/* Created by Josef Soucek, 2003.  E-mail: josef.soucek@ct.cz */

/* 2003-01-21 -- Version 0.1 */
/* 2009-10-10 -- Version 0.3 */
/* 2011-04-07 -- Version 0.4, groepaz */
/* 2011-04-14 -- Version 0.5, Greg King */

/* Tested with floppy-drive and IDE64 devices.        */
/* Not tested with messed (buggy) directory listings. */
/* Limits filenames to 16 chars. (VICE supports more  */
/* in directory listings).                            */


#include <cbm.h>
#include <errno.h>

#pragma code-name("DPCODE");
//#pragma rodata-name("DPCODE");

unsigned char __fastcall__ cbm_opendir2(unsigned char lfn, unsigned char device, char * command)
{
	if (cbm_open (lfn, device, CBM_READ, command) == 0) {
		if ((_oserror = cbm_k_chkin (lfn)) == 0) {
			/* Ignore start address */
			cbm_k_basin();
			cbm_k_basin();
			cbm_k_clrch();
			if (cbm_k_readst()) {
				cbm_close(lfn);
				_oserror = 4;           /* directory cannot be read */
			}
		}
	}
	return _oserror;
}

/* Opens directory listing.
** Returns 0 if openning directory was successful;
** otherwise, an error-code corresponding to cbm_open().
*/
unsigned char __fastcall__ cbm_opendir (unsigned char lfn, unsigned char device)
{
	return cbm_opendir2(lfn, device, "$");
}



/* Reads one directory line into cbm_dirent structure.
** Returns 0 if reading directory-line was successful.
** Returns non-zero if reading directory failed, or no more file-names to read.
** Returns 2 on last line.  Then, l_dirent->size = the number of "blocks free."
*/
unsigned char __fastcall__ cbm_readdir (unsigned char lfn, register struct cbm_dirent* l_dirent)
{
	unsigned char byte, i = 0;
	unsigned char is_header = 0;
	unsigned char rv = 1;
	static const unsigned char types[] = {
		CBM_T_CBM,   CBM_T_DEL,   CBM_T_OTHER, CBM_T_OTHER, /* c d e f */
		CBM_T_OTHER, CBM_T_OTHER, CBM_T_OTHER, CBM_T_OTHER, /* g h i j */
		CBM_T_OTHER, CBM_T_LNK,   CBM_T_OTHER, CBM_T_OTHER, /* k l m n */
		CBM_T_OTHER, CBM_T_PRG,   CBM_T_OTHER, CBM_T_REL,   /* o p q r */
		CBM_T_SEQ,   CBM_T_OTHER, CBM_T_USR,   CBM_T_VRP    /* s t u v */
	};

	if (!cbm_k_chkin(lfn)) {
		if (!cbm_k_readst()) {
			/* skip 2 bytes, next-BASIC-line pointer */
			cbm_k_basin();
			cbm_k_basin();

			/* File-size or drive/partition number */
			l_dirent->size = cbm_k_basin() | (cbm_k_basin() << 8);

			byte = cbm_k_basin();
			switch (byte) {

				/* "B" BLOCKS FREE. */
			  case 'b':
				/* Read until end; careless callers might call us again. */
				while (!cbm_k_readst()) {
					cbm_k_basin();
				}
				rv = 2; /* EOF */
				goto ret_val;

				/* Reverse-text shows when this is the directory header. */
			  case 0x12:  /* RVS_ON */
				is_header = 1;
			}

			while (byte != '\"') {
				/* prevent endless loop */
				if (cbm_k_readst()) {
					rv = 3;
					goto ret_val;
				}
				byte = cbm_k_basin();
			}

			while ((byte = cbm_k_basin()) != '\"') {
				/* prevent endless loop */
				if (cbm_k_readst()) {
					rv = 4;
					goto ret_val;
				}

				if (i < sizeof (l_dirent->name) - 1) {
					l_dirent->name[i] = byte;
					++i;
				}
			}
			l_dirent->name[i] = '\0';

			if (is_header) {
				l_dirent->type = CBM_T_HEADER;

		/* Get the disk-format code. */
		i = 6;
		do {
			l_dirent->access = byte = cbm_k_basin();
		} while (--i != 0);

			} else {
				/* Go to the file-type column. */
				while ((byte = cbm_k_basin()) == ' ') {
					/* prevent endless loop */
					if (cbm_k_readst()) {
						rv = 5;
						goto ret_val;
					}
				}

				l_dirent->access = CBM_A_RW;

				/* "Splat" files shouldn't be read. */
				if (byte == '*') {
					l_dirent->access = CBM_A_WO;
					byte = cbm_k_basin();
				}

				if (byte >= 'c' && byte < 'c' + sizeof types) {
					l_dirent->type = types[byte - 'c'];
				} else {
					l_dirent->type = CBM_T_OTHER;
				}

		/* Notice whether it's a directory or a deleted file. */
		if (cbm_k_basin() == 'i' && byte == 'd') {
			l_dirent->type = CBM_T_DIR;
		}
				cbm_k_basin();

				/* Locked files shouldn't be written. */
				if ((byte = cbm_k_basin()) == '<') {
					l_dirent->access = (l_dirent->access == CBM_A_WO)
						? 0 : CBM_A_RO;
				}
			}

			/* Read to the end of the line. */
			while (byte != 0) {
				/* prevent endless loop */
				if (cbm_k_readst()) {
					rv = 6;
					goto ret_val;
				}
				byte = cbm_k_basin();
			}

			rv = 0;
			goto ret_val;
		}
	}

ret_val:
	cbm_k_clrch();
	return rv;
}



void __fastcall__ cbm_closedir (unsigned char lfn)
{
	cbm_close(lfn);
}


